fix(platform): Fix Google Drive auto-credentials handling across the platform - #12004
fix(platform): Fix Google Drive auto-credentials handling across the platform#12004ntindle wants to merge 9 commits into
Conversation
…platform - Tag auto-credentials with `is_auto_credential` and `input_field_name` on `CredentialsFieldInfo` to distinguish them from regular user-provided credentials - Add `regular_credentials_inputs` and `auto_credentials_inputs` properties to `Graph` so UI schemas, CoPilot, and library presets only surface regular credentials - Extract `_acquire_auto_credentials()` helper in executor to resolve embedded `_credentials_id` at execution time with proper lock management - Validate auto-credentials ownership in `_validate_node_input_credentials()` to catch stale/missing credentials before execution - Clear `_credentials_id` in `_reassign_ids()` on graph fork so cloned agents require re-authentication - Propagate `is_auto_credential` through `combine()` and `discriminate()` on `CredentialsFieldInfo` - Add `referrerPolicy: "no-referrer-when-downgrade"` to Google API script loading to fix Firefox API key validation - Comprehensive test coverage for all new behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds metadata to credential fields to distinguish auto vs regular credentials; exposes Graph.regular_credentials_inputs and Graph.auto_credentials_inputs; clears _credentials_id on Graph._reassign_ids; excludes auto-credentials from static matching/presets; implements runtime auto-credential acquisition/validation with tests and a small frontend script tweak. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Executor
participant Graph
participant CredManager as "Creds Manager"
Client->>Executor: execute_node(block, input_data, user_id)
Executor->>Graph: get_auto_credentials_fields()
Graph-->>Executor: auto_credentials fields
rect rgba(100,200,100,0.5)
loop per auto_credential field
Executor->>Executor: extract field_data and _credentials_id
alt _credentials_id present
Executor->>CredManager: acquire(user_id, cred_id)
CredManager-->>Executor: credentials + lock
Executor->>Executor: inject credentials into exec_kwargs
else _credentials_id missing or None
Executor->>Executor: skip or raise (per field rules)
end
end
end
Executor->>Executor: run node with exec_kwargs
Executor->>CredManager: release credential locks (finally)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR improves Google Drive “auto-credentials” handling end-to-end by explicitly tagging auto-generated credentials, excluding them from user-facing credential mapping flows, validating ownership earlier, and resolving embedded _credentials_id at execution time with clearer error behavior (plus a small frontend fix for Google script loading in Firefox).
Changes:
- Adds
is_auto_credential+input_field_nametoCredentialsFieldInfoand propagates them throughcombine()/discriminate(). - Introduces
Graph.regular_credentials_inputs/Graph.auto_credentials_inputsand updates executor/chat/library flows to use regular credentials only for UI/schema/matching. - Extracts
_acquire_auto_credentials()in the executor and adds auto-credential validation; updates Google script loading withreferrerPolicy.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/helpers.ts | Sets script referrerPolicy for Google API loaders. |
| autogpt_platform/backend/backend/executor/utils_test.py | Adds tests covering auto-credential validation and regular-only mapping. |
| autogpt_platform/backend/backend/executor/utils.py | Validates auto-credentials and maps only regular graph credentials inputs. |
| autogpt_platform/backend/backend/executor/manager_auto_credentials_test.py | New test suite for _acquire_auto_credentials() behavior and edge cases. |
| autogpt_platform/backend/backend/executor/manager.py | Extracts auto-credential acquisition helper and wires it into node execution. |
| autogpt_platform/backend/backend/data/model.py | Adds auto-credential fields to CredentialsFieldInfo and propagates in combine/discriminate. |
| autogpt_platform/backend/backend/data/graph_test.py | Adds tests for propagation, schema exclusion, and fork clearing of _credentials_id. |
| autogpt_platform/backend/backend/data/graph.py | Adds regular_credentials_inputs/auto_credentials_inputs and clears _credentials_id on fork. |
| autogpt_platform/backend/backend/data/block.py | Tags auto-credentials in get_credentials_fields_info() output. |
| autogpt_platform/backend/backend/api/features/library/db.py | Uses regular_credentials_inputs to gate preset creation. |
| autogpt_platform/backend/backend/api/features/chat/tools/utils_test.py | New tests ensuring chat tools exclude auto-credentials. |
| autogpt_platform/backend/backend/api/features/chat/tools/utils.py | Switches credential aggregation to regular_credentials_inputs. |
Adapt auto-credentials filtering to dev's refactored graph model: - aggregate_credentials_inputs() now returns 3-tuples (field_info, node_pairs, is_required) - credentials_input_schema moved to GraphModel, builds JSON schema directly - Update regular/auto_credentials_inputs properties for 3-tuple format - Update test mocks and assertions for new tuple format and class hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
autogpt_platform/backend/backend/api/features/chat/tools/utils.py (1)
226-248:⚠️ Potential issue | 🟡 MinorStale docstring references
aggregate_credentials_inputs().Line 233 still says "Uses graph.aggregate_credentials_inputs()" but the implementation now uses
regular_credentials_inputs. This will confuse future readers.📝 Proposed fix
- Uses graph.aggregate_credentials_inputs() which handles credentials from - multiple nodes and uses frozensets for provider matching. + Uses graph.regular_credentials_inputs which handles credentials from + multiple nodes (excluding auto-credentials) and uses frozensets for provider matching.
🤖 Fix all issues with AI agents
In `@autogpt_platform/backend/backend/executor/utils.py`:
- Around line 355-366: The auto-credentials branch calling get_creds_by_id on
creds_store (in the block handling field_value dicts) lacks error handling and
can raise from the credentials store; wrap the await
creds_store.get_creds_by_id(user_id, cred_id) call in a try/except like the
regular credentials path so store failures set has_missing_credentials=True and
populate credential_errors[node.id][field_name] with an appropriate message
(include context that the credentials store failed) instead of letting the
exception propagate; reference get_integration_credentials_store,
creds_store.get_creds_by_id, credential_errors, node.id, and field_name when
making the change.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (9)
autogpt_platform/backend/backend/api/features/chat/tools/utils.pyautogpt_platform/backend/backend/api/features/chat/tools/utils_test.pyautogpt_platform/backend/backend/api/features/library/db.pyautogpt_platform/backend/backend/data/block.pyautogpt_platform/backend/backend/data/graph.pyautogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/data/model.pyautogpt_platform/backend/backend/executor/utils.pyautogpt_platform/backend/backend/executor/utils_test.py
🚧 Files skipped from review as they are similar to previous changes (4)
- autogpt_platform/backend/backend/data/model.py
- autogpt_platform/backend/backend/api/features/library/db.py
- autogpt_platform/backend/backend/data/block.py
- autogpt_platform/backend/backend/api/features/chat/tools/utils_test.py
🧰 Additional context used
📓 Path-based instructions (10)
autogpt_platform/backend/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
autogpt_platform/backend/**/*.py: Use Python 3.11 (required; managed by Poetry via pyproject.toml) for backend development
Always run 'poetry run format' (Black + isort) before linting in backend development
Always run 'poetry run lint' (ruff) after formatting in backend development
Files:
autogpt_platform/backend/backend/executor/utils.pyautogpt_platform/backend/backend/api/features/chat/tools/utils.pyautogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.pyautogpt_platform/backend/backend/data/graph.py
autogpt_platform/backend/**/*.{py,txt}
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use
poetry runprefix for all Python commands, including testing, linting, formatting, and migrations
Files:
autogpt_platform/backend/backend/executor/utils.pyautogpt_platform/backend/backend/api/features/chat/tools/utils.pyautogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.pyautogpt_platform/backend/backend/data/graph.py
autogpt_platform/backend/backend/**/*.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
Use Prisma ORM for database operations in PostgreSQL with pgvector for embeddings
Files:
autogpt_platform/backend/backend/executor/utils.pyautogpt_platform/backend/backend/api/features/chat/tools/utils.pyautogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.pyautogpt_platform/backend/backend/data/graph.py
autogpt_platform/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Format Python code with
poetry run format
Files:
autogpt_platform/backend/backend/executor/utils.pyautogpt_platform/backend/backend/api/features/chat/tools/utils.pyautogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.pyautogpt_platform/backend/backend/data/graph.py
autogpt_platform/backend/backend/api/features/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Update routes in '/backend/backend/api/features/' and add/update Pydantic models in the same directory for API development
When modifying API routes, update corresponding Pydantic models in the same directory and write tests alongside the route file
Files:
autogpt_platform/backend/backend/api/features/chat/tools/utils.py
autogpt_platform/backend/backend/api/**/*.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
autogpt_platform/backend/backend/api/**/*.py: Use FastAPI for building REST and WebSocket endpoints
Use JWT-based authentication with Supabase integration
Files:
autogpt_platform/backend/backend/api/features/chat/tools/utils.py
autogpt_platform/backend/backend/data/**/*.py
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
All data access in backend requires user ID checks; verify this for any 'data/*.py' changes
Files:
autogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/data/graph.py
autogpt_platform/backend/**/*_test.py
📄 CodeRabbit inference engine (autogpt_platform/backend/CLAUDE.md)
autogpt_platform/backend/**/*_test.py: Always review snapshot changes withgit diffbefore committing when updating snapshots withpoetry run pytest --snapshot-update
Use pytest with snapshot testing for API responses in test files
Colocate test files with source files using the*_test.pynaming convention
Files:
autogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.py
autogpt_platform/backend/**/*test*.py
📄 CodeRabbit inference engine (AGENTS.md)
Run
poetry run testfor backend testing (runs pytest with docker based postgres + prisma)
Files:
autogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.py
autogpt_platform/**/data/*.py
📄 CodeRabbit inference engine (AGENTS.md)
For changes touching
data/*.py, validate user ID checks or explain why not needed
Files:
autogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/data/graph.py
🧠 Learnings (2)
📚 Learning: 2026-02-04T16:50:51.303Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-04T16:50:51.303Z
Learning: Applies to autogpt_platform/**/data/*.py : For changes touching `data/*.py`, validate user ID checks or explain why not needed
Applied to files:
autogpt_platform/backend/backend/executor/utils.pyautogpt_platform/backend/backend/data/graph.py
📚 Learning: 2026-02-04T16:49:42.476Z
Learnt from: CR
Repo: Significant-Gravitas/AutoGPT PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-02-04T16:49:42.476Z
Learning: Applies to autogpt_platform/backend/**/test/**/*.py : Use snapshot testing with '--snapshot-update' flag in backend tests when output changes; always review with 'git diff'
Applied to files:
autogpt_platform/backend/backend/data/graph_test.pyautogpt_platform/backend/backend/executor/utils_test.py
🧬 Code graph analysis (4)
autogpt_platform/backend/backend/executor/utils.py (4)
autogpt_platform/backend/backend/data/graph.py (2)
block(131-140)regular_credentials_inputs(607-615)autogpt_platform/backend/backend/data/block.py (1)
get_auto_credentials_fields(274-302)autogpt_platform/backend/backend/util/clients.py (1)
get_integration_credentials_store(113-117)autogpt_platform/backend/backend/integrations/credentials_store.py (1)
get_creds_by_id(382-386)
autogpt_platform/backend/backend/api/features/chat/tools/utils.py (1)
autogpt_platform/backend/backend/data/graph.py (1)
regular_credentials_inputs(607-615)
autogpt_platform/backend/backend/data/graph_test.py (2)
autogpt_platform/backend/backend/data/model.py (3)
CredentialsFieldInfo(566-696)combine(578-673)discriminate(675-696)autogpt_platform/backend/backend/data/graph.py (3)
Graph(378-381)name(1713-1714)_reassign_ids(646-686)
autogpt_platform/backend/backend/executor/utils_test.py (4)
autogpt_platform/backend/backend/executor/utils.py (2)
_validate_node_input_credentials(239-380)make_node_credentials_input_map(383-416)autogpt_platform/backend/backend/data/graph.py (1)
regular_credentials_inputs(607-615)autogpt_platform/backend/backend/data/model.py (2)
CredentialsFieldInfo(566-696)CredentialsMetaInput(496-554)autogpt_platform/backend/backend/integrations/providers.py (1)
ProviderName(6-108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: Seer Code Review
- GitHub Check: e2e_test
- GitHub Check: types
- GitHub Check: Seer Code Review
- GitHub Check: Cursor Bugbot
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: test (3.13)
- GitHub Check: Analyze (python)
- GitHub Check: Check PR Status
🔇 Additional comments (10)
autogpt_platform/backend/backend/data/graph.py (2)
606-626: LGTM — clean separation of regular vs. auto credentials.The filter-based properties are straightforward and correctly delegate to
aggregate_credentials_inputs(). Theis_auto_credentialflag on the tuple's first element is the right discriminator.One minor note: both properties independently call
aggregate_credentials_inputs(), so if both are accessed in the same code path the aggregation runs twice. This isn't a concern today (not a hot path), but worth keeping in mind if usage grows.
678-686: Good security hardening — clearing_credentials_idon fork.The loop correctly targets only
dict-typed values containing_credentials_id, leaving other fields intact. This prevents credential leakage when a graph is forked to another user.autogpt_platform/backend/backend/api/features/chat/tools/utils.py (1)
120-120: LGTM — auto-credentials correctly excluded from missing-credentials computation.autogpt_platform/backend/backend/executor/utils_test.py (2)
918-972: Good test coverage for auto-credential validation paths.The four auto-credential validation tests (valid, missing, both, None-skip) provide solid coverage of the
_validate_node_input_credentialsauto-credential branch. The mock structures correctly mirror theget_auto_credentials_fields()return format.
1192-1241:make_node_credentials_input_mapexclusion test is solid.The test correctly verifies that only regular credentials appear in the output map by asserting no
_credentials_idvalues leak through. The mock ofregular_credentials_inputsas a property (rather thanaggregate_credentials_inputs) matches the production code path.autogpt_platform/backend/backend/executor/utils.py (2)
343-366: Auto-credentials validation logic looks correct.The implementation properly:
- Extracts
_credentials_idfrom file-field data- Skips when
_credentials_idisNone(upstream-chained)- Validates ownership via
get_creds_by_id- Reports a user-friendly error when credentials aren't found
One thing to note: the error message on line 363 is hardcoded to "Google credentials". If auto-credentials expand beyond Google Drive in the future, this will need generalization.
399-401: LGTM —make_node_credentials_input_mapcorrectly scoped to regular credentials only.autogpt_platform/backend/backend/data/graph_test.py (3)
466-526: Good regression tests forcombine()field propagation.Both tests (auto and regular) verify that
is_auto_credentialandinput_field_namesurvive the combine operation. These directly guard against the bug class described in the PR.
531-673: Thorough_reassign_idscredential clearing tests.Good coverage of edge cases: single credential field, preserving non-credential fields, no credentials present, and multiple credential fields. These directly validate the security fix.
728-789:credentials_input_schemaexclusion test is well-structured.Using
PropertyMockto controlregular_credentials_inputsisolates the schema generation logic cleanly.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Wrap get_creds_by_id call in try/except in the auto-credentials validation path to match the error handling pattern used for regular credentials. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ⓘ Your monthly quota for Qodo has expired. Upgrade your plan ⓘ Paying users. Check that your Qodo account is linked with this Git user account |
4 similar comments
ⓘ Your monthly quota for Qodo has expired. Upgrade your plan ⓘ Paying users. Check that your Qodo account is linked with this Git user account |
ⓘ Your monthly quota for Qodo has expired. Upgrade your plan ⓘ Paying users. Check that your Qodo account is linked with this Git user account |
ⓘ Your monthly quota for Qodo has expired. Upgrade your plan ⓘ Paying users. Check that your Qodo account is linked with this Git user account |
ⓘ Your monthly quota for Qodo has expired. Upgrade your plan ⓘ Paying users. Check that your Qodo account is linked with this Git user account |
Resolved conflicts: - executor/utils.py: kept auto-credentials validation + dev's comment update - graph_test.py: kept both auto-credentials tests AND MCP deduplication tests
|
Conflicts have been resolved! 🎉 A maintainer will review the pull request shortly. |
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🔴 Merge Conflicts DetectedThe following PRs have been tested and will have merge conflicts if merged after this PR. Consider coordinating with the authors.
🟢 Low Risk — File Overlap OnlyThese PRs touch the same files but different sections (click to expand)
Summary: 3 conflict(s), 0 medium risk, 6 low risk (out of 9 PRs with file overlap) Auto-generated on push. Ignores: |
|
This pull request has conflicts with the base branch, please resolve those so we can evaluate the pull request. |
autogpt-reviewer
left a comment
There was a problem hiding this comment.
📋 PR #12004 — fix(platform): Fix Google Drive auto-credentials handling across the platform
Author: ntindle | Files: 12 changed (+1238/−45) | Reviewed by: 8-specialist automated review squad
🎯 Verdict: APPROVE WITH CONDITIONS
What This PR Does
Separates "auto-credentials" (embedded in Google Drive file picker fields via _credentials_id) from regular user-provided credentials across the platform. Auto-credentials no longer appear in UI credential forms, CoPilot "missing credentials" prompts, or library preset guards. Forking an agent now clears embedded credential references to prevent cross-user credential leakage. Also fixes Firefox blocking Google API script loads via referrerPolicy.
Specialist Findings
🛡️ Security ✅ — Credential ownership is properly user-scoped via user_id in all acquire() and get_creds_by_id calls. Fork clearing in _reassign_ids() correctly prevents cross-user credential reuse. No credential leakage paths identified. Two low-severity notes: partial lock cleanup on multi-field failure (mitigated by Redis TTL) and non-recursive dict clearing (sufficient for current GoogleDriveFile model).
🏗️ Architecture ✅ — Design is fundamentally sound. The is_auto_credential/input_field_name fields on CredentialsFieldInfo are generic enough to extend to other providers. Clean separation between regular and auto credential paths. Suggestions: extract _credentials_id as a named constant (used as magic string in 4+ locations), add explicit guard in run_block.py for auto-credential blocks until SECRT-1911 is addressed, and consider a shared state-parser for the 5-state dict semantics.
⚡ Performance regular_credentials_inputs and auto_credentials_inputs are uncached @property methods that each independently call aggregate_credentials_inputs(). In a single request flow, this can run the full aggregation 2-3x. Additionally, _validate_node_input_credentials calls get_integration_credentials_store() and get_creds_by_id per auto-credential field (N+1 pattern). Current impact is low (only Google Drive auto-creds exist), but should be cached.
🧪 Testing ✅ — Excellent coverage with ~1,056 lines of new tests across 4 files. Tests are well-structured with ticket references (SECRT-1772, OPEN-2895), descriptive names, and realistic mocks. All tests confirmed running (no skip markers), CI passes on 3.11/3.12/3.13. Gaps: no test for multi-field lock stranding failure path, no test for _credentials_id key-missing scenario in validation, no test for get_creds_by_id exception path, no test for empty-string _credentials_id.
📖 Quality match_user_credentials_to_graph() still references aggregate_credentials_inputs() instead of regular_credentials_inputs (flagged by CodeRabbit, not yet fixed).
📦 Product ✅ — Complete fix for all primary user-facing issues. All 4 consumer paths (CoPilot prompts, credential input schema, library presets, execution mapping) updated to exclude auto-credentials. Fork clearing gives users clear, actionable error messages guiding re-authentication. Firefox referrerPolicy fix uses universal browser-supported values. Deferred run_block.py gap (SECRT-1911) is narrow and well-documented.
📬 Discussion =None to del). Follow-up PR #12016 created for code duplication concern. 2 minor items unaddressed: stale docstring and credential ID in error message.
🔎 QA ✅ — Frontend loads correctly across all pages (landing, copilot, build, marketplace, library). Google Drive File Input Block renders on canvas. Backend healthy. referrerPolicy change properly implemented in loadScript helper. No PR-related console errors. Full Google OAuth flow untestable in local env (requires real credentials), but backend logic is thoroughly unit-tested.
QA Screenshots:
Conditions (must address before merge)
- Resolve merge conflicts — PR has been in conflict since Feb 17. Must rebase/merge from base branch.
- Fix stale docstring —
match_user_credentials_to_graph()inchat/tools/utils.py:233still referencesaggregate_credentials_inputs(). Update to referenceregular_credentials_inputs.
Should Fix (follow-up OK)
- Cache
aggregate_credentials_inputs()— Use@cached_propertyor lazy init to avoid 2-3x redundant computation per request flow (graph.py:619-637). - Extract
_credentials_idas named constant — Magic string used in 4+ locations acrossmanager.py,utils.py,graph.py,_base.py. DefineAUTO_CREDENTIALS_ID_KEY = "_credentials_id". - Hoist
get_integration_credentials_store()— Currently re-instantiated per iteration in validation loop (utils.py:369). Move outside the loop. - Add
run_block.pyguard — Explicit check that blocks with auto-credentials can't be run viaRunBlockTooluntil SECRT-1911 is addressed. Currently would give confusing errors. - Add edge-case tests — Multi-field lock stranding,
_credentials_idkey-missing in validation,get_creds_by_idexception path, empty-string credential ID.
Nice to Have
- Include credential ID in error messages for easier debugging (CodeRabbit suggestion)
- Consistent section header formatting in
graph_test.py auto_credentials_inputsproperty is currently dead code — add a comment noting it's for future use or remove
Risk Assessment
Merge risk: LOW — Well-tested (1056 lines of new tests, CI green), security model is sound, all existing tests pass. Changes are additive (new fields/properties) with minimal modification of existing logic.
Rollback: EASY — The new fields have defaults (is_auto_credential=False, input_field_name=None), so reverting wouldn't break existing data. The fork clearing and validation are new code paths that would simply be removed.
@ntindle This is a solid, well-tested security and UX fix. The credential separation design is clean and extensible. Main blockers are the merge conflicts and one stale docstring. Once those are resolved, this is good to merge. The should-fix items (caching, constant extraction, run_block guard) can follow up.
Pull request was closed
…2269) (Significant-Gravitas#12874) ### Why / What / How **Why:** A beta user spent significant time trying to build and run agents that read Google Sheets. Four separate failures compounded on their session — all already open in Linear as SECRT-2266 through SECRT-2269. Three in-flight PRs each addressed a piece but conflicted on the same files (`backend/data/model.py`, `backend/blocks/_base.py`, `autogpt_libs/.../types.py`), so landing them individually would have been churn. One of the four reported issues (the credential-delete crash) is also the top unresolved Sentry issue `AUTOGPT-SERVER-6HB` with 100+ events going back to 2025-10-20 — it was archived as "ignored" but is a real regression. Bug Significant-Gravitas#4 required new work; the others we got by adopting the existing open PRs and addressing a pending review comment. **What:** This PR consolidates the three in-flight PRs, adds the two pieces of new work needed to fully close the beta blockers, and addresses the pending review on one of the three PRs so it doesn't require a second round. - **Closes PR Significant-Gravitas#12004** — Google Drive auto-credentials handling (merged in) - **Closes PR Significant-Gravitas#12748** — Incremental OAuth for scope upgrades (merged in) - **Closes PR Significant-Gravitas#12588** — superseded by the systemic None-guard here (see "How" below) - **Adds Bug 2 fix** — Google credential deletion no longer crashes on `revoke_tokens` - **Adds Bug 4 validator** — the agent builder can no longer save a graph with a hardcoded Drive file ID **How:** 1. **Adopt PR Significant-Gravitas#12004 (Bug 1 — auto-credentials resolution).** Tags Drive-file fields as `is_auto_credential` on `CredentialsFieldInfo`, exposes `BlockSchema.get_auto_credentials_fields()` and `Graph.regular_credentials_inputs` / `auto_credentials_inputs`, extracts `_acquire_auto_credentials()` in the executor to resolve embedded `_credentials_id` at run time, clears `_credentials_id` on agent fork so cloned agents don't inherit the original author's credential, and fixes the Firefox referrer policy on the Google Drive picker script load. 2. **Adopt PR Significant-Gravitas#12748 (Bug 3 — credential accumulation).** OAuth callback now merges scopes into an existing credential (explicit via `credential_id` in OAuth state, or implicit via `provider + username` match) instead of appending a new row on every reconnect. GitHub's non-incremental OAuth path requests the union of existing + new scopes at login so the upgrade path works there too. 3. **Replace PR Significant-Gravitas#12588 with a systemic None-guard (addresses reviewer feedback).** The original PR added a per-block `credentials: GoogleCredentials | None = None` + early guard pattern that would need to be repeated across 50+ blocks with `GoogleDriveFileField`. Per the reviewer's ask, we moved the guard into `Block._execute()` once: after the `setdefault` loop, if `kwargs[kwarg_name] is None` we raise `BlockExecutionError` with a clean user-facing message. The per-block change in `sheets.py` is dropped so `credentials: GoogleCredentials` stays non-`Optional`. Dry-run path skips the guard (executor intentionally runs blocks without resolved creds for schema validation). 4. **Fix Bug 2 — Google revoke_tokens (SECRT-2267, AUTOGPT-SERVER-6HB).** `revoke_tokens()` was handing our Pydantic `OAuth2Credentials` into google-auth's `AuthorizedSession`, which calls `self.credentials.before_request(...)` on the object and crashes with `AttributeError: 'OAuth2Credentials' object has no attribute 'before_request'`. Google's token revoke endpoint doesn't need any auth header — just `token=<token>` in the form body per [Google's docs](https://developers.google.com/identity/protocols/oauth2/web-server#tokenrevoke). Switched to the platform's async `Requests` helper, matching how `reddit.py` / `github.py` / `todoist.py` / other providers do revocation. No google-auth objects involved. 5. **Fix Bug 4 — hardcoded Drive file IDs in agent graphs (SECRT-2269).** Evidence from the beta user's session: CoPilot's agent-builder produced 13 saved graph versions in one session where each one stuffed either a bare string (`"1KAv…"`) or a partial object (`{"id": "1KAv…"}`) into `GoogleSheetsReadBlock.constantInput.spreadsheet`, never wiring an `AgentGoogleDriveFileInputBlock` as the intended input. Bare-string versions failed pydantic validation with `is not of type 'object'`; object-with-only-`id` versions would have crashed at run time because `_acquire_auto_credentials` has no `_credentials_id` to resolve. Added a validator in `GraphModel._validate_graph_get_errors` that flags any auto-credentials field whose `input_default.<field>` is a bare string OR a dict missing `_credentials_id`, when there's no upstream link feeding the field. Remediation text is format-aware: when `field_schema["format"] == "google-drive-picker"` it names `AgentGoogleDriveFileInputBlock` specifically; for any other future auto-credentials format (OneDrive / Dropbox / etc.) the remediation is generic, so we don't ship a stale Google-specific hint that doesn't apply. A companion handoff for the CoPilot agent-builder team is drafted at `/tmp/agent-builder-ticket-drive-file-input.md` (to be filed in their tracker). The validator here is a safety net so reviewers and the LLM both get a clear error with the correct remediation; the agent-builder itself still needs to learn the correct pattern so it stops trying to hardcode Drive files in the first place. ### Changes 🏗️ **Backend** - `backend/data/model.py` — merged `is_auto_credential` + `input_field_name` (Significant-Gravitas#12004) with `OAuthState.credential_id` (Significant-Gravitas#12748); kept HEAD's defensive `set()` copy on `discriminator_values`. - `backend/blocks/_base.py` — `_execute()` runs the auto-credentials setdefault loop + raises `BlockExecutionError` when a resolved value is `None`. - `backend/blocks/google/sheets_test.py` — 2 new tests (systemic None-guard behaviour). - `backend/blocks/google/_drive.py`, `_drive_test.py` — unchanged on this branch (earlier bare-string validator was reverted after feedback; see "Out of scope" below). - `backend/data/graph.py` — auto-credentials anti-pattern validator in `_validate_graph_get_errors`. - `backend/data/graph_test.py` — 11 new tests for the validator. - `backend/integrations/oauth/google.py` — `revoke_tokens` swapped to `Requests().post`, removed `AuthorizedSession` misuse. - `backend/integrations/oauth/google_test.py` — 3 new tests covering the revoke happy path, no-access-token, and non-2xx-response. - `backend/integrations/credentials_store.py` — from Significant-Gravitas#12748. - `backend/api/features/integrations/router.py` — incremental-OAuth callback + scope upgrade helpers (from Significant-Gravitas#12748). - `backend/api/features/integrations/incremental_oauth_test.py` — 15 tests (from Significant-Gravitas#12748). - `backend/api/features/chat/tools/utils.py` → renamed to `backend/copilot/tools/utils.py` during merge; now uses `regular_credentials_inputs` for missing-creds + matching (from Significant-Gravitas#12004). - `backend/copilot/tools/utils_test.py` — moved from `api/features/chat/tools/`, import paths updated. - `backend/api/features/library/db.py` — library preset guard uses `regular_credentials_inputs` (from Significant-Gravitas#12004). - `backend/data/graph.py` — `regular_credentials_inputs` / `auto_credentials_inputs` properties + `_reassign_ids` clears `_credentials_id` on fork (from Significant-Gravitas#12004). - `backend/executor/manager.py` — `_acquire_auto_credentials()` extracted + validation (from Significant-Gravitas#12004). - `backend/executor/utils.py`, `utils_test.py`, `manager_auto_credentials_test.py` — auto-credentials tests (from Significant-Gravitas#12004). **Frontend** - `frontend/src/components/contextual/GoogleDrivePicker/helpers.ts` — Firefox referrer fix (from Significant-Gravitas#12004). - `frontend/src/components/contextual/CredentialsInput/useCredentialsInput.ts`, `src/hooks/useCredentials.ts`, `src/lib/autogpt-server-api/client.ts`, `src/providers/agent-credentials/credentials-provider.tsx`, `src/app/api/openapi.json` — incremental-OAuth scope upgrade UI (from Significant-Gravitas#12748). **Shared libs** - `autogpt_libs/supabase_integration_credentials_store/types.py` — merged additions from both Significant-Gravitas#12004 and Significant-Gravitas#12748. ### Test plan 📋 - [x] `poetry run lint` — clean - [x] `poetry run pytest backend/data/graph_test.py` — 55 passed including 11 new validator tests - [x] `poetry run pytest backend/integrations/oauth/google_test.py` — 3 new tests passing - [x] `poetry run pytest backend/blocks/google/sheets_test.py` — 2 new tests passing - [x] `poetry run pytest backend/blocks/google/ backend/integrations/oauth/ backend/executor/ backend/data/graph_test.py backend/api/features/integrations/ backend/copilot/tools/utils_test.py` — 250 passed, 6 pre-existing failures that require the docker stack (RabbitMQ/Redis/Postgres) and fail identically on `origin/dev` - [x] `pnpm format` — clean - [x] `pnpm lint` — 3 pre-existing `<img>` warnings on files I didn't touch, no errors - [x] `pnpm types` — pre-existing errors on `AgentActivityDropdown` that also fail on `origin/dev` (unrelated to this PR; needs a separate fix on dev) - [x] Live repro on dev verified Bug 2 fires against current prod code — two fresh Sentry events in `AUTOGPT-SERVER-6HB` at 2026-04-21T21:35:54Z on `app:dev-behave:cloud` matching the exact `DELETE /api/integrations/google/credentials/{cred_id}` path. Airtable OAuth2 delete as a control worked cleanly, confirming Google-specific. - [x] Live repro on dev verified Bug 4 (CoPilot direct-run variant) — `{"spreadsheet": {"id": "..."}}` → `Cannot use file 'None' (type: None)` from `_validate_spreadsheet_file` mimeType check, as expected. Reviewer post-merge verification: - [ ] Delete a Google OAuth credential via the Integrations UI — succeeds cleanly, no Sentry event fires - [ ] Connect Google twice (same account, same scopes) — credential count stays at 1 (dedup) - [ ] Save an agent graph with `GoogleSheetsReadBlock.constantInput.spreadsheet = "bare-id"` via API — graph validator rejects with `AgentGoogleDriveFileInputBlock` remediation - [ ] Save an agent graph with `GoogleSheetsReadBlock` whose `spreadsheet` is fed by an upstream `AgentGoogleDriveFileInputBlock.result` — validator accepts, agent runs ### Out of scope (for follow-ups) - **Bug 1 — "Failed to retrieve Google OAuth credentials"** in `frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts:163`. Zero hits for this string in the beta user's Langfuse traces and we weren't able to reproduce it from a clean flow. Most likely a stale-credential race condition (delete in another tab, picker queries a stale React-Query cache). Tracked as a separate task; not blocking. - **CoPilot first-attempt mimeType retry loop.** Observed on dev: CoPilot's first call to `GoogleSheetsReadBlock` sends `{"spreadsheet": {"id": "..."}}` without `mimeType`, hits `_validate_spreadsheet_file`, retries with mimeType. Costs a round-trip. Two possible fixes (relax `_validate_spreadsheet_file` to skip when mimeType is `None` and let Google's API surface the real error; OR extend `get_auto_credentials_fields` metadata so CoPilot's tool description prompts it to always include mimeType). Deliberately deferred — fixing only one of "API caller sends a bare string" or "CoPilot sends an incomplete object" risked the same auth-ambiguity the bare-string commit in this branch history hit. - **CoPilot agent-builder prompt/guide update.** The validator here produces the correct error message, but the agent-builder model still needs to learn to use `AgentGoogleDriveFileInputBlock` upfront rather than discover it through validator retries. Separate handoff ticket filed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches OAuth credential issuance/upgrade paths and introduces a new endpoint that returns raw access tokens (scope-gated), plus broad changes to execution-time credential resolution/validation; mistakes could impact auth/security or break integrations. > > **Overview** > Fixes several Google/Drive agent-builder blockers by **supporting incremental OAuth scope upgrades** and by hardening how credential-bearing file inputs (“auto-credentials”) are validated, resolved, and cleared on graph fork. > > On the integrations API, `/{provider}/login` now accepts `credential_id` and persists it in `OAuthState` to upgrade an existing OAuth2 credential on callback (explicit upgrade), with an implicit merge path for same `provider+username`. The callback path now merges scopes/metadata, preserves ID/title, preserves existing `refresh_token`/`username` when missing from incremental responses, blocks upgrades for managed/system credentials, and adds a **new `/{provider}/credentials/{cred_id}/picker-token` endpoint** to return a short-lived access token for provider-hosted pickers (currently allowlisted to Google Drive scopes). > > For auto-credentials, `CredentialsFieldInfo` gains `is_auto_credential` + `input_field_name`, graphs now expose `regular_credentials_inputs` vs `auto_credentials_inputs`, and multiple callers switch from `aggregate_credentials_inputs()` to `regular_credentials_inputs` so embedded picker credentials aren’t treated as user-mapped inputs. Execution-time auto-credential acquisition is extracted into `_acquire_auto_credentials()` with clearer error handling and lock cleanup; block execution adds a systemic guard to surface a clean `Missing credentials` error when auto-credentials are absent. > > Separately fixes Google credential deletion by rewriting `GoogleOAuthHandler.revoke_tokens()` to use the platform `Requests` helper (bounded retries) instead of `AuthorizedSession`, and expands test coverage across these flows (incremental OAuth, picker-token, auto-credential validation/acquisition, graph validator, and frontend diagnostics test stubs). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit cac36ea. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Google Drive file picker blocks embed a
_credentials_idin the file field data, but the platform had no way to distinguish these "auto-credentials" from regular user-provided credentials. This caused auto-credentials to appear in UI credential forms, CoPilot "missing credentials" prompts, and library preset guards — confusing users. Additionally, forking an agent didn't clear the embedded credential references, so cloned agents could silently use the original author's Google credentials. Finally, Firefox's strict referrer policy was blocking Google API script loads.Changes 🏗️
Backend — Data model (
model.py,block.py,graph.py)CredentialsFieldInfogainsis_auto_credentialandinput_field_namefields to tag auto-credentialsBlockSchema.get_auto_credentials_fields()returns auto-credential metadata for executionGraph.regular_credentials_inputs/auto_credentials_inputsproperties filter aggregated credentials_reassign_ids()clears_credentials_idon fork to prevent cross-user credential leakagecombine()anddiscriminate()propagateis_auto_credentialandinput_field_nameBackend — Executor (
manager.py,utils.py)_acquire_auto_credentials()extracted as standalone async helper to resolve embedded_credentials_idat execution time with Redis lock management_validate_node_input_credentials()validates auto-credential ownership before executionmake_node_credentials_input_map()usesregular_credentials_inputsonlyBackend — CoPilot & Library (
chat/tools/utils.py,library/db.py)build_missing_credentials_from_graph()andmatch_user_credentials_to_graph()useregular_credentials_inputsso auto-credentials aren't reported as "missing"regular_credentials_inputsFrontend (
GoogleDrivePicker/helpers.ts)referrerPolicy: "no-referrer-when-downgrade"to both Google API script loads (gapi + picker) to fix Firefox blockingKnown deferred:
run_block.py(CoPilotRunBlockTool) still includes auto-credentials in credential matching — tracked as SECRT-1911Checklist 📋
For code changes:
manager_auto_credentials_test.py— 6 tests covering credential acquisition, error cases, chained datautils_test.py— 8 tests covering auto-credential validation, fork clearing, mixed credential graphsgraph_test.py— 5 tests coveringregular_credentials_inputs,auto_credentials_inputs, schema exclusion,combine(),discriminate()propagationchat/tools/utils_test.py— 2 tests covering CoPilot credential filteringFor configuration changes:
.env.defaultis updated or already compatible with my changesdocker-compose.ymlis updated or already compatible with my changesNote
Medium Risk
Touches credential schema aggregation and executor credential acquisition/validation paths; while well-tested, mistakes could block runs or incorrectly prompt for credentials across many agents.
Overview
Fixes Google Drive auto-credentials end-to-end by tagging them in
CredentialsFieldInfo(is_auto_credential,input_field_name) and splitting graph credential aggregation intoregular_credentials_inputsvsauto_credentials_inputs, so only regular creds appear in graph schemas, CoPilot “missing credentials” prompts, credential mapping, and preset eligibility checks.Strengthens execution-time handling for file-embedded
_credentials_id: forks now strip_credentials_idto prevent cross-user credential reuse, executor validation checks auto-credential ownership/missing auth, and execution resolves auto-creds via a new_acquire_auto_credentials()helper with clearer error messages; adds extensive regression tests and setsreferrerPolicyon Google script loads to avoid Firefox blocking.Written by Cursor Bugbot for commit c42aab3. This will update automatically on new commits. Configure here.