Skip to content

AAP-68153 Add workload identity for inventory sync jobs#16380

Draft
davemulford wants to merge 1 commit intoansible:develfrom
davemulford:AAP-68153-oidc-inventory-sync
Draft

AAP-68153 Add workload identity for inventory sync jobs#16380
davemulford wants to merge 1 commit intoansible:develfrom
davemulford:AAP-68153-oidc-inventory-sync

Conversation

@davemulford
Copy link
Copy Markdown

@davemulford davemulford commented Apr 1, 2026

SUMMARY

Adds OIDC workload identity support to inventory sync jobs.

RunInventoryUpdate had two gaps preventing OIDC workload identity tokens from reaching the cloud credential during inventory sync:

  1. build_credentials_list() called get_extra_credentials() which excludes the cloud credential, so populate_workload_identity_tokens() never generated a JWT for it.

  2. The inventory plugin injector calls inventory_update.get_cloud_credential() internally, which does a fresh DB fetch that loses the OIDC context set by populate_workload_identity_tokens().

Fix (1) by returning all credentials with prefetched input sources.
Fix (2) by overriding get_cloud_credential() on the instance to return the credential that already carries the OIDC context.

ISSUE TYPE
  • New or Enhanced Feature
COMPONENT NAME
  • Other (awx/main/tasks/jobs)

Summary by CodeRabbit

Bug Fixes

  • Optimized credential retrieval in inventory updates through enhanced database query patterns for improved performance.
  • Improved cloud credential processing during inventory updates to ensure proper context preservation and reliable execution throughout the workflow.
  • Enhanced stability and efficiency of inventory credential handling operations.

RunInventoryUpdate had two gaps preventing OIDC workload identity
tokens from reaching the cloud credential during inventory sync:

1. build_credentials_list() called get_extra_credentials() which
   excludes the cloud credential, so populate_workload_identity_tokens()
   never generated a JWT for it.

2. The inventory plugin injector calls inventory_update.get_cloud_credential()
   internally, which does a fresh DB fetch that loses the OIDC context
   set by populate_workload_identity_tokens().

Fix (1) by returning all credentials with prefetched input sources.
Fix (2) by overriding get_cloud_credential() on the instance to return
the credential that already carries the OIDC context.

Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

Modified RunInventoryUpdate.build_credentials_list() to return a prefetch-optimized queryset of all inventory update credentials with related input source data. Updated build_env() to conditionally override inventory_update.get_cloud_credential with a contextualized credential from the internal credentials collection, preventing fresh database fetches that would lose OIDC token context.

Changes

Cohort / File(s) Summary
Inventory Update Credential Handling
awx/main/tasks/jobs.py
Modified build_credentials_list() to use prefetch_related('input_sources__source_credential').all() for complete credential data; updated build_env() to conditionally override get_cloud_credential method with contextualized credential to preserve OIDC token context and avoid fresh DB fetches.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main feature being added: workload identity support for inventory sync jobs, which is the core objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@awx/main/tasks/jobs.py`:
- Around line 1731-1739: The current patch only overrides
inventory_update.get_cloud_credential to return a credential instance from
self._credentials, but inventory_update code may call
inventory.get_extra_credentials() which rebuilds from self.credentials.all() and
will return fresh DB instances lacking the workload-identity context; update the
same injector override logic to also replace
inventory_update.get_extra_credentials with a lambda that returns the extras
from the prefetched/context-bearing snapshot (i.e., derive extras by filtering
self._credentials for credential.kind/usage matching what get_extra_credentials
would return) so both single credential access (get_cloud_credential) and bulk
extras access (get_extra_credentials) return the contexted instances.
- Around line 1875-1878: The change returns every inventory_update credential
into self._credentials which causes BaseTask.run() to inject injector-owned
credentials twice; instead, leave _credentials semantics unchanged (so
BaseTask.run() continues to iterate only credentials meant for
inject_credential()), and create a separate snapshot used only for
workload-identity token generation (e.g., call
populate_workload_identity_tokens() with an all_credentials variable set from
inventory_update.credentials.prefetch_related('input_sources__source_credential').all());
update the code around the existing method (where
inventory_update.credentials.prefetch_related(...) was added) to return or
assign only the original injectable credentials for _credentials while keeping
the full list in a distinct name used solely by
populate_workload_identity_tokens().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3d023b75-3e6d-4df2-83f6-77d246700863

📥 Commits

Reviewing files that changed from the base of the PR and between e80ce43 and 73daffe.

📒 Files selected for processing (1)
  • awx/main/tasks/jobs.py

Comment on lines +1731 to +1739
# The injector's _get_shared_env() calls inventory_update.get_cloud_credential()
# which does a fresh DB fetch, losing the OIDC context populated by
# populate_workload_identity_tokens(). Override it on this instance to return
# the credential from self._credentials which already has the context.
cloud_cred = inventory_update.get_cloud_credential()
if cloud_cred and self._credentials:
contexted_cred = next((c for c in self._credentials if c.pk == cloud_cred.pk), None)
if contexted_cred is not None:
inventory_update.get_cloud_credential = lambda _cred=contexted_cred: _cred
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This only fixes one of the inventory credential accessors.

In awx/main/models/inventory.py, Lines 1059-1074, get_extra_credentials() still rebuilds its list from self.credentials.all(). Anything in the inventory-update injector path that resolves extras through that accessor will still get fresh instances without the workload-identity token context, so the fix remains partial unless extras are also returned from the same prefetched/context-bearing snapshot.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@awx/main/tasks/jobs.py` around lines 1731 - 1739, The current patch only
overrides inventory_update.get_cloud_credential to return a credential instance
from self._credentials, but inventory_update code may call
inventory.get_extra_credentials() which rebuilds from self.credentials.all() and
will return fresh DB instances lacking the workload-identity context; update the
same injector override logic to also replace
inventory_update.get_extra_credentials with a lambda that returns the extras
from the prefetched/context-bearing snapshot (i.e., derive extras by filtering
self._credentials for credential.kind/usage matching what get_extra_credentials
would return) so both single credential access (get_cloud_credential) and bulk
extras access (get_extra_credentials) return the contexted instances.

Comment on lines +1875 to +1878
# Include all credentials (cloud + extra) with prefetch so that
# populate_workload_identity_tokens() can generate OIDC JWTs for
# credentials whose input sources reference an OIDC external credential.
return inventory_update.credentials.prefetch_related('input_sources__source_credential').all()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Returning all credentials here changes runtime injection semantics.

Line 1878 widens _credentials from “credentials that should run generic inject_credential() logic” to every inventory-update credential. But BaseTask.run() injects every entry in self._credentials on Lines 715-718, while InventoryUpdate.get_extra_credentials() exists specifically to keep the injector-owned credential out of that loop (awx/main/models/inventory.py, Lines 1059-1074). That can double-inject the special credential and clobber injector-managed env/file state; keep a separate all-credentials snapshot for workload-identity token generation instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@awx/main/tasks/jobs.py` around lines 1875 - 1878, The change returns every
inventory_update credential into self._credentials which causes BaseTask.run()
to inject injector-owned credentials twice; instead, leave _credentials
semantics unchanged (so BaseTask.run() continues to iterate only credentials
meant for inject_credential()), and create a separate snapshot used only for
workload-identity token generation (e.g., call
populate_workload_identity_tokens() with an all_credentials variable set from
inventory_update.credentials.prefetch_related('input_sources__source_credential').all());
update the code around the existing method (where
inventory_update.credentials.prefetch_related(...) was added) to return or
assign only the original injectable credentials for _credentials while keeping
the full list in a distinct name used solely by
populate_workload_identity_tokens().

Copy link
Copy Markdown
Contributor

@PabloHiro PabloHiro left a comment

Choose a reason for hiding this comment

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

LGTM. I wonder if there is a way to add a test for this though. So in case this gets refactored in the future, we don't introduce regressions.

if cloud_cred and self._credentials:
contexted_cred = next((c for c in self._credentials if c.pk == cloud_cred.pk), None)
if contexted_cred is not None:
inventory_update.get_cloud_credential = lambda _cred=contexted_cred: _cred
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is so so hacky, but I explored the code and I think there is no other way to do it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is kind of crazy. The right answer would be a deeper refactor.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You make the call here @AlanCoding , want us to dig deeper here or leave it as is for now until it becomes a problem?

@davemulford
Copy link
Copy Markdown
Author

I've moved this PR to draft status because #16382 may end up making these changes unnecessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants